1.12 Preprocessor Directives in C Programming
Module 1.12 • Preprocessing Mechanics, Macros Expansion & Conditional Compilation
1.12.1 Introduction
Before a C program is compiled, it passes through a special stage called preprocessing. During this stage, instructions known as Preprocessor Directives are processed.
These directives:
- Begin with the # symbol
- Do not end with a semicolon
- Are executed before compilation
- Help in code organization and optimization
Compilation Flow
Source Code
↓
Preprocessor
↓
Compiler
↓
Object Code
↓
Executable Program
1.12.2 Features of Preprocessor Directives
Characteristics
- Start with #
- Processed before compilation
- No semicolon required
- Can appear anywhere in the program
- Commonly placed at the beginning
Example:
#include <stdio.h>
#define LIMIT 100
1.12.3 Common Preprocessor Directives
| Directive | Purpose |
|---|---|
#include | Include files |
#define | Create constants/macros |
#undef | Remove macro definition |
#if | Conditional compilation |
#ifdef | Check if macro exists |
#ifndef | Check if macro does not exist |
#else | Alternative condition |
#elif | Additional condition |
#endif | End condition block |
#pragma | Compiler-specific instruction |
#error | Generate custom compile error |
#line | Change line information |
1.12.4 The #include Directive
Used to include external files.
Standard Library Header
#include <stdio.h>
Compiler searches predefined system folders.
User Defined Header
#include "student.h"
Compiler searches current folder first.
1.12.5 Why Use Header Files?
Header files contain:
- Function declarations
- Macro definitions
- Structure declarations
- Constants
Example:
#include "math_utils.h"
Benefits:
- Reusable code
- Better organization
- Easier maintenance
1.12.6 The #define Directive
Used to create symbolic constants.
Example
#define TAX_RATE 18
Usage:
total = amount + TAX_RATE;
The preprocessor replaces TAX_RATE with 18.
1.12.7 Symbolic Constants Example
#include <stdio.h>
#define MAX_STUDENTS 60
int main()
{
printf("Maximum Students = %d", MAX_STUDENTS);
return 0;
}
Output:
Maximum Students = 60
1.12.8 Macro Expansion
Macros can replace text.
#define MESSAGE "Welcome to Coding Hub"
Example:
printf(MESSAGE);
Expands to:
printf("Welcome to Coding Hub");
1.12.9 Macros with Arguments
Macros can accept parameters.
Syntax
#define MACRO(parameter) expansion
Example:
#define DOUBLE(x) ((x)+(x))
1.12.10 Example Program
#include <stdio.h>
#define DOUBLE(x) ((x)+(x))
int main()
{
int value = 14;
printf("%d", DOUBLE(value));
return 0;
}
Output:
28
1.12.11 Area Calculation Macro
#define RECT_AREA(l,w) ((l)*(w))
Program:
#include <stdio.h>
#define RECT_AREA(l,w) ((l)*(w))
int main()
{
printf("%d", RECT_AREA(8,5));
return 0;
}
Output:
40
1.12.12 Maximum Macro
#define MAX(a,b) ((a)>(b)?(a):(b))
Example:
MAX(35,21)
Result:
35
1.12.13 Minimum Macro
#define MIN(a,b) ((a)<(b)?(a):(b))
Example:
MIN(42,15)
Result:
15
1.12.14 Importance of Parentheses
Incorrect:
#define MULTIPLY(x,y) x*y
Using:
MULTIPLY(3+2,4+1)
Expands to:
3+2*4+1
Result:
12
Expected:
25
1.12.15 Correct Macro Design
Correct version:
#define MULTIPLY(x,y) ((x)*(y))
Now:
MULTIPLY(3+2,4+1)
Expands to:
((3+2)*(4+1))
Result:
25
1.12.16 Nested Macros
One macro can use another.
#define RATE 12
#define DOUBLE_RATE (RATE*2)
Example:
salary = DOUBLE_RATE;
Expands to:
salary = (12*2);
1.12.17 Example of Nested Macros
#include <stdio.h>
#define LOWER(c) ((c)>='a' && (c)<='z')
#define ALPHA(c) (LOWER(c) || ((c)>='A' && (c)<='Z'))
int main()
{
char ch='G';
if(ALPHA(ch))
printf("Alphabet");
return 0;
}
Output:
Alphabet
1.12.18 Macro vs Function
| Feature | Macro | Function |
|---|---|---|
| Speed | Faster | Slightly slower |
| Memory | More | Less |
| Type Checking | No | Yes |
| Debugging | Difficult | Easier |
| Safety | Lower | Higher |
1.12.19 When to Use Macros?
Good for:
- Small calculations
- Constants
- Fast replacements
Example:
#define PI 3.14159
Avoid macros for:
- Complex logic
- Large operations
- Recursive behavior
1.12.20 The #undef Directive
Removes a macro definition.
Example
#define LIMIT 500
#undef LIMIT
After removal, LIMIT is no longer recognized.
1.12.21 Example of #undef
#include <stdio.h>
#define VERSION 2
int main()
{
printf("%d\n",VERSION);
#undef VERSION
return 0;
}
Output:
2
1.12.22 Conditional Compilation
Sometimes code should compile only under certain conditions. Used directives:
- #if
- #ifdef
- #ifndef
- #else
- #elif
- #endif
1.12.23 The #if Directive
Example
#define LEVEL 5
#if LEVEL > 3
printf("Advanced User");
#endif
Output:
Advanced User
1.12.24 #if Example Program
#include <stdio.h>
#define MARKS 85
int main()
{
#if MARKS >= 50
printf("Pass");
#endif
return 0;
}
Output:
Pass
1.12.25 The #else Directive
#define TEMP 20
#if TEMP > 30
printf("Hot");
#else
printf("Pleasant");
#endif
Output:
Pleasant
1.12.26 The #elif Directive
#define GRADE 2
#if GRADE==1
printf("Excellent");
#elif GRADE==2
printf("Very Good");
#elif GRADE==3
printf("Good");
#else
printf("Average");
#endif
Output:
Very Good
1.12.27 The #ifdef Directive
Checks whether a macro exists.
#define TEST_MODE
Example:
#ifdef TEST_MODE
printf("Testing Enabled");
#endif
Output:
Testing Enabled
1.12.28 The #ifndef Directive
Checks whether macro does not exist.
#ifndef BUFFER_SIZE
#define BUFFER_SIZE 256
#endif
Used frequently in header files.
1.12.29 Header Guard Example
#ifndef STUDENT_H
#define STUDENT_H
struct Student
{
int roll;
};
#endif
Prevents duplicate inclusion.
1.12.30 The defined Operator
Used with #if.
Example:
#if defined(DEBUG)
printf("Debug Build");
#endif
1.12.31 Multiple Macro Check
#if defined(USER) && defined(PASSWORD)
printf("Login Enabled");
#endif
1.12.32 Debugging Using Macros
#define DEBUG
Program:
#ifdef DEBUG
printf("Function Started\n");
#endif
Output:
Function Started
1.12.33 Disabling Debug Messages
Simply remove:
#define DEBUG
Now debug messages disappear automatically.
1.12.34 The #error Directive
Creates compile-time error messages.
Example:
#ifndef VERSION
#error VERSION not defined
#endif
Compiler Output:
VERSION not defined
1.12.35 The #line Directive
Changes line number information.
Example:
#line 200
Compiler treats next line as line 200.
1.12.36 The #pragma Directive
Provides compiler-specific instructions.
Example:
#pragma warning(disable:4996)
Used mainly for:
- Warning control
- Optimization
- Compiler settings
1.12.37 Predefined Macros
C automatically provides predefined macros.
| Macro | Description |
|---|---|
__DATE__ | Compilation date |
__TIME__ | Compilation time |
__FILE__ | Current file name |
__LINE__ | Current line number |
__STDC__ | ANSI C support |
1.12.38 Displaying Compilation Information
#include <stdio.h>
int main()
{
printf("%s\n",__DATE__);
printf("%s\n",__TIME__);
return 0;
}
Output Example:
Jun 15 2026
14:32:10
1.12.39 Using FILE
printf("%s", __FILE__);
Possible Output:
main.c
1.12.40 Using LINE
printf("%d", __LINE__);
Output:
25
(Depends on actual line number.)
1.12.41 Stringizing Operator (#)
Converts macro arguments into strings.
Example
#define DISPLAY(x) printf(#x)
Usage:
DISPLAY(Programming)
Output:
Programming
1.12.42 Stringizing Example
#include <stdio.h>
#define SHOW(v) printf(#v " = %d",v)
int main()
{
int marks = 92;
SHOW(marks);
return 0;
}
Output:
marks = 92
1.12.43 Token Pasting Operator (##)
Combines two tokens.
Example:
#define JOIN(a,b) a##b
Usage:
JOIN(score,1)
Produces:
score1
1.12.44 Token Pasting Example
#include <stdio.h>
#define JOIN(a,b) a##b
int main()
{
int roll1 = 110;
printf("%d", JOIN(roll,1));
return 0;
}
Output:
110
1.12.45 Advantages of Preprocessor Directives
- Improves readability
- Reduces repetitive code
- Simplifies maintenance
- Supports portability
- Enables conditional compilation
- Helps debugging
1.12.46 Applications
- Embedded Systems
- Operating Systems
- Device Drivers
- Game Development
- Networking Software
- Compiler Design
Summary
- Preprocessor executes before compilation.
- #include adds external files.
- #define creates constants and macros.
- #undef removes macros.
- #if, #ifdef, #ifndef control compilation.
- #error generates compile-time errors.
- #pragma provides compiler instructions.
- __DATE__, __TIME__, __FILE__, and __LINE__ are predefined macros.
- # and ## operators provide advanced macro capabilities.
- Preprocessor directives improve flexibility, portability, and maintainability of C programs.
Click your choice for each question to view feedback immediately. Complete all questions to evaluate your metric score.